package com.license.logic.ontology;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntClass;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.ontology.OntProperty;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;
import com.license.common.util.Constants;

public class OntologyJenaParser {

	private HashMap<String, List<Individual>> individuals = new HashMap<String , List<Individual>>();
	private HashMap<String, OntClass> ontoClasses = new HashMap<String ,OntClass>();
	private HashMap<String,List<OntProperty>> properties = new HashMap<String ,List<OntProperty>>();
	private OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM_MICRO_RULE_INF);
	
	public OntologyJenaParser() {
		setUp();
	}
	
	public void setUp() {
		InputStream in = FileManager.get().open(Constants.ONTOLOGYLOCATION);
		if (in == null) {
			throw new IllegalArgumentException("File: "
					+ Constants.ONTOLOGYLOCATION + "not found");
		}
		// read the RDF/XML file
		model.read(in, null);
	}
	
	public void parseOntology() throws IOException {
		// for every class from ontology
		ExtendedIterator<OntClass> ontClasses = model.listClasses();
		while (ontClasses.hasNext()) {
			OntClass ontClass = ontClasses.next();

			if (ontClass.getLocalName() != null
					&& ontClass.getURI().equals(Constants.NS + ontClass.getLocalName())) {
				ontoClasses.put(ontClass.getLocalName(), ontClass);
				individuals.put(ontClass.getLocalName(), getIndividualsFromOntClass(ontClass));
				properties.put(ontClass.getLocalName(), getPropertiesOfOntClass(ontClass));
				System.out.println("Classes == " + ontClass.getURI());
			}
		}
		System.out.println(properties.get("food"));
	}
	
	public List<OntClass> setUpAllToOntoClasses() {

		List<OntClass> ontClasses = new ArrayList<OntClass>();
		// for every class from ontology
		for (ExtendedIterator<OntClass> ontologyClass = model.listClasses(); ontologyClass.hasNext();) {
			
			OntClass ontClass = ontologyClass.next();
			if (ontClass != null && !(ontClass.getLocalName().equals(Constants.ONTOLOGY_ROOT))
								 && !(ontClass.getLocalName().equals(Constants.GENERIC_ONT_CLASS))) {
				// add subclasses for every class that have subclasses in ontology
				if (ontClass.listSubClasses() != null
						&& ontClass.listSubClasses().toList().size() > 0) {
					for (OntClass subClass : getSubClassesOfOntClass(ontClass)) {

						ontClass.setSubClass(subClass);
					}
				}
				// add superclasses for every class that have subclasses in
				if (ontClass.listSuperClasses() != null
						&& ontClass.listSuperClasses().toList().size() > 0) {
					for (OntClass superClass : getSuperClassesOfOntClass(ontClass)) {

						ontClass.setSuperClass(superClass);
					}
				}
				// add properties
				if (ontClass.listProperties() != null
						&& ontClass.listProperties().toList().size() > 0) {
					for (OntProperty propertie : getPropertiesOfOntClass(ontClass)) {

						ontClass.setPropertyValue((Property) propertie,
								ontClass);
					}
				}
				ontClasses.add(ontClass);
			}
		}
		return ontClasses;
	}

	public List<Individual> getIndividualsFromOntClass(OntClass ontClass) {
		
		if (ontClass.listInstances() != null
				&& ontClass.listInstances().toList().size() > 0 
				&& !(ontClass.getLocalName().equals(Constants.ONTOLOGY_ROOT))) {
			
			List<Individual> individuals = new ArrayList<Individual>();
			@SuppressWarnings("unchecked")
			ExtendedIterator<Individual> individualsIt = (ExtendedIterator<Individual>) ontClass.listInstances();

			while (individualsIt.hasNext()) {
				Individual individual = individualsIt.next();
				individuals.add(individual);
				System.out.println("Individuals ==" + individual);
			}
			return individuals;
		}
		else return null;
	}
	
	public List<String> getIndividualsFromOntClassByName(String ontClassName) {
		
		String ontClassURI = Constants.NS + ontClassName;
		List<String> individuals = new ArrayList<String>();
		List<Individual> ontIndividuals = new ArrayList<Individual>();
		ExtendedIterator<OntClass> ontClasses = model.listClasses();
		while (ontClasses.hasNext()) {
			OntClass ontClass = ontClasses.next();

			if (ontClass.getLocalName() != null	&& ontClass.getURI().equals(ontClassURI)) {
				ontIndividuals = getIndividualsFromOntClass(ontClass);
			}
		}
		for(Individual individ : ontIndividuals) {
			individuals.add(individ.getLocalName());
		}
		return individuals;
	}
	
	public List<OntClass> getSubClassesOfOntClass(OntClass ontClass) {
		
		if (ontClass.listSubClasses() != null
				&& ontClass.listSubClasses().toList().size() > 0) {
			
			List<OntClass> ontClasses = new ArrayList<OntClass>();
			ExtendedIterator<OntClass> subClassesIt = ontClass.listSubClasses();

			while (subClassesIt.hasNext()) {
				OntClass ontSubClass = subClassesIt.next();
				if(!(ontSubClass.getLocalName().equals(Constants.GENERIC_ONT_CLASS)) &&
						!(ontSubClass.getLocalName().equals(Constants.ONTOLOGY_ROOT))) {
					ontClasses.add(ontSubClass);
				}
				
			}
			return ontClasses;
		}
		else return null;
	}
	
	public List<OntProperty> getPropertiesOfOntClass(OntClass ontClass) {
		
		if(ontClass.listProperties() != null && ontClass.listProperties().toList().size() > 0) {
			
			List<OntProperty> properties = new ArrayList<OntProperty>();
			ExtendedIterator<OntProperty> propertiesIt = ontClass.listDeclaredProperties();
			
			while( propertiesIt.hasNext()) {
				OntProperty propertie = propertiesIt.next();
				properties.add(propertie);
				System.out.println("Propertie ===" + propertie);
			}
			return properties;
		}
		else return null;
	}
	
	public List<String> getPropertyOfOntClassByName(String ontClassName) {
		
		String ontClassURI = Constants.NS + ontClassName;
		List<OntProperty> ontProperties = new ArrayList<OntProperty>();
		List<String> properties = new ArrayList<String>();
		ExtendedIterator<OntClass> ontClasses = model.listClasses();
		while (ontClasses.hasNext()) {
			OntClass ontClass = ontClasses.next();

			if (ontClass.getLocalName() != null	&& ontClass.getURI().equals(ontClassURI)) {
				ontProperties = getPropertiesOfOntClass(ontClass);
			}
		}
		for(OntProperty ontProperty : ontProperties) {
			 properties.add(ontProperty.getLocalName());
		}
		
		return properties;
	}
	
	public List<OntClass> getSuperClassesOfOntClass(OntClass ontClass) {
	
		if (ontClass.listSuperClasses() != null
				&& ontClass.listSuperClasses().toList().size() > 0) {
			
			List<OntClass> ontClasses = new ArrayList<OntClass>();
			ExtendedIterator<OntClass> superClassesIt = ontClass.listSuperClasses();

			while (superClassesIt.hasNext()) {
				OntClass ontSuperClass = superClassesIt.next();
				if(!(ontSuperClass.getLocalName().equals(Constants.GENERIC_ONT_CLASS)) &&
						!(ontSuperClass.getLocalName().equals(Constants.ONTOLOGY_ROOT))) {
					ontClasses.add(ontSuperClass);
				}
			}
			return ontClasses;
		}
		else return null;
	}
}
